-- 罗盘页面
module(..., package.seeall)

-- 当前界面有没有被展示
local isShow = false

-- 存储校准数据
local kbTab = {}

-- 目标角度
local destA = 0
-- 当前角度
local nowA = 0
-- 最小转动角度
local minA = 20

-- 一阶滤波
function fof(a)
    local fofA = a or 0.01
    local fofLast = 0
    return function(n)
        n = n or 0
        local ret = n*fofA+fofLast*(1-fofA)
        fofLast = n
        return ret
    end
end

funcX = fof()
funcY = fof()

function angle()
    if not isShow then
        return
    end
    if not(kbTab.midx and kbTab.midy) then
        return
    end
    local x, y = myiic.getMag()
    if not (x and y) then
        return
    end
    -- 计算角度
    destA = math.deg(math.atan2((x-kbTab.midx)*kbTab.kx, (y-kbTab.midy)))*10
end

function draw()
    if not isShow then
        return
    end
    -- 更新角度
    angle()
    -- if nowA~=destA and math.abs(nowA-destA)>minA+1  then
    --     -- 用 1/10 的速率转动
    --     local da = (nowA-destA)/10
    --     da = da < minA and minA or da
    --     nowA = nowA - da
    -- end
    -- log.info("compass", nowA)
    page.compassAngle = destA
end
local helpTxt = "请水平转动四圈"
function kb()
    -- 采集个数, 至少要 100 个点
    local n = 500
    -- 标准大约 (100-250)
    local criterion = 200
    local minx, miny, maxx, maxy
    local tx = {}
    local ty = {}
    -- 数据采集 校准时间是 n*20 ms
    for i=1, n do
        if not isShow then
            -- 如果界面退出, 停止校准
            return false, "校准停止"
        end
        log.info("compass", "校准中:", i/n)
        sys.wait(20)
        local x, y = myiic.getMag()
        if x and y then
            tx[#tx+1] = x
            ty[#ty+1] = y
        end
    end
    if #tx > n/2 and #ty > n/2 then
        -- 数据采集成功
        table.sort(tx)
        table.sort(ty)

        -- 数值可能大于标准, 否则需要怀疑根本没动 
        if tx[#tx]-tx[1] < criterion or ty[#ty]-ty[1] < criterion then
            return false, "校准失败,"..helpTxt
        end
        -- 计算中值
        midx = (tx[1]+tx[2]+tx[3]+tx[#tx-0]+tx[#tx-1]+tx[#tx-2])/6
        midy = (ty[1]+ty[2]+ty[3]+ty[#ty-0]+ty[#ty-1]+ty[#ty-2])/6
        subx = (tx[#tx-0]+tx[#tx-1]+tx[#tx-2]-tx[1]-tx[2]-tx[3])/6
        suby = (ty[#ty-0]+ty[#ty-1]+ty[#ty-2]-ty[1]-ty[2]-ty[3])/6
        log.info("jzy", ty[#ty-0], ty[#ty-1], ty[#ty-2], ty[1], ty[2], ty[3])
        log.info("jzx", tx[#ty-0], tx[#ty-1], tx[#ty-2], tx[1], tx[2], tx[3])
        if suby==0 then
            return false, "校准失败,"..helpTxt
        end
        kbTab.midx = midx
        kbTab.midy = midy
        kbTab.kx = suby/subx
        nvm.set("kbTab", kbTab)
        log.info("midx, midy, kx", midx, midy, suby/subx)
        return true
    else
        -- 数据采集失败
        return false, "校准失败, 数据无法采集"
    end
end

function uiShow(msg)
    if not isShow then
        return
    end
    page.compassTxt = msg or " "
    if msg then
        page.compassAngle = 0
        page.compassOpa1 = 25
        page.compassOpa2 = 25
    else
        page.compassAngle = 0
        page.compassOpa1 = 255
        page.compassOpa2 = 255
    end
end

-- 指方向
local lock = false
function news()
    if tools.testMode then
        return
    end
    if not myiic.enable then
        -- iic 异常
        uiShow("iic 异常")
        log.info("compass", "iic 异常")
        return
    end
    if myiic.is6050 then
        -- 该版本不支持 罗盘 功能
        uiShow("该版本不支持罗盘功能")
        log.info("compass", "该版本不支持罗盘功能")
        return
    end
    kbTab = nvm.get("kbTab") or {}
    if kbTab.midx and kbTab.midy then
        -- 已经校准完了, 开始动
        uiShow()
        log.info("compass", "校准完毕")
        sys.timerLoopStart(draw, 20)
        return
    end
    -- 开始校准
    sys.taskInit(function()
        if lock then return end
        uiShow("校准中,"..helpTxt)
        local f, msg = kb()
        if not f then
            -- 校准失败
            uiShow("校准失败,点击确认重新开始")
            log.info("compass", "校准失败")
        else
            -- 成功, 开始动作
            uiShow()
            log.info("compass", "校准完毕")
            sys.timerLoopStart(draw, 20)
        end
        lock = false
    end)
end

function enter()  
    isShow = true
    page.compassAngle = 0
    news()
end

function exit() 
    isShow = false
    sys.timerStop(draw)
end

function keyOkShort() 
    kbTab.midx = nil
    kbTab.midy = nil
    nvm.set("kbTab", {})
    news()
end